package net.simflow.swf.analyzer.network.opt;

import java.net.URI;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.HashSet;

import net.simflow.swf.analyzer.network.data.Flow;
import net.simflow.swf.analyzer.network.data.Instance;
import net.simflow.swf.analyzer.network.data.Network;
import net.simflow.swf.analyzer.network.data.Node;
import net.simflow.swf.analyzer.network.data.Service;

public class NetworkMerger {

	private static NetworkMerger instance = new NetworkMerger();

	private NetworkMerger() {
	}

	public static NetworkMerger getInstance() {
		return instance;
	}

	public Network merge(HashSet<Flow> flowSet) {
		if (flowSet == null) {
			return null;
		}

		try {
			Network nw = new Network();

			HashMap<URI, Service> usm = new HashMap<URI, Service>();
			HashMap<Service, Node> snm = new HashMap<Service, Node>();

			for (Flow flow : flowSet) {
				for (Node node : flow.getNodeSet()) {
					Service svc = node.getService();
					if (svc.getWsdlURI() != null) {
						Service existsvc = usm.get(svc.getWsdlURI());
						if (existsvc == null) {
							usm.put(svc.getWsdlURI(), svc);
						} else {
							if (existsvc != svc
									&& existsvc.getWsdlURI().equals(
											svc.getWsdlURI())) {
								for (Instance ins : svc.getInstanceSet()) {
									existsvc.addInstance(ins);
								}
								flow.getServiceSet().remove(svc);
								node.setService(existsvc);
								flow.addService(existsvc);
								svc = existsvc;
							}
						}
					}
					Node netnode = snm.get(svc);
					if (netnode == null) {
						netnode = new Node(svc);
						snm.put(svc, netnode);
					}
				}
				for (Node parent : flow.getNodeSet()) {
					Node parentnetnode = snm.get(parent.getService());
					for (Node child : parent.getChildDataSet()) {
						Node childnetnode = snm.get(child.getService());
						if (childnetnode != parentnetnode) {
							parentnetnode.addChildData(childnetnode);
							childnetnode.addParentData(parentnetnode);
						}
					}
					for (Node child : parent.getChildControlSet()) {
						Node childnetnode = snm.get(child.getService());
						if (childnetnode != parentnetnode) {
							parentnetnode.addChildControl(childnetnode);
							childnetnode.addParentControl(parentnetnode);
						}
					}
				}
			}

			NumberFormat format = NumberFormat.getIntegerInstance();
			format.setMinimumIntegerDigits(5);
			format.setGroupingUsed(false);
			int c;

			c = 0;
			for (Flow flow : flowSet) {
				String name = "Flow" + format.format(c) + "_" + flow.getName();
				nw.addFlow(flow, name);
				c++;
			}

			nw.addAllNode(snm.values());

			c = 0;
			for (Service s : snm.keySet()) {
				String name = "Service" + format.format(c);
				nw.addService(s, name);
				c++;
				nw.addAllInstance(s.getInstanceSet());
			}

			c = 0;
			for (Node n : nw.getNodeSet()) {
				n.setNameInNetwork("Node" + format.format(c));
				c++;
			}

			for (Flow f : nw.getFlowMap().values()) {
				for (Node n : f.getNodeSet()) {
					n.setNameInNetwork("Node" + format.format(c));
					c++;
				}
			}

			return nw;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}
